home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
nethack.lha
/
nethack-3.1
/
src
/
mkobj.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-18
|
18KB
|
762 lines
/* SCCS Id: @(#)mkobj.c 3.1 93/01/17 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "artifact.h"
#include "prop.h"
STATIC_DCL void FDECL(mkbox_cnts,(struct obj *));
struct icp {
int iprob; /* probability of an item type */
char ilet; /* item class */
};
#ifdef OVL1
const struct icp mkobjprobs[] = {
{10, WEAPON_CLASS},
{10, ARMOR_CLASS},
{20, FOOD_CLASS},
{ 8, TOOL_CLASS},
{ 8, GEM_CLASS},
{16, POTION_CLASS},
{16, SCROLL_CLASS},
{ 4, SPBOOK_CLASS},
{ 4, WAND_CLASS},
{ 3, RING_CLASS},
{ 1, AMULET_CLASS}
};
const struct icp boxiprobs[] = {
{18, GEM_CLASS},
{15, FOOD_CLASS},
{18, POTION_CLASS},
{18, SCROLL_CLASS},
{12, SPBOOK_CLASS},
{ 7, GOLD_CLASS},
{ 6, WAND_CLASS},
{ 5, RING_CLASS},
{ 1, AMULET_CLASS}
};
#ifdef REINCARNATION
const struct icp rogueprobs[] = {
{12, WEAPON_CLASS},
{12, ARMOR_CLASS},
{22, FOOD_CLASS},
{22, POTION_CLASS},
{22, SCROLL_CLASS},
{ 5, WAND_CLASS},
{ 5, RING_CLASS}
};
#endif
const struct icp hellprobs[] = {
{20, WEAPON_CLASS},
{20, ARMOR_CLASS},
{16, FOOD_CLASS},
{12, TOOL_CLASS},
{10, GEM_CLASS},
{ 1, POTION_CLASS},
{ 1, SCROLL_CLASS},
{ 8, WAND_CLASS},
{ 8, RING_CLASS},
{ 4, AMULET_CLASS}
};
static int NEARDATA mksx=0, NEARDATA mksy=0;
struct obj *
mkobj_at(let,x,y, artif)
char let;
int x,y;
boolean artif;
{
register struct obj *otmp;
mksx = x; mksy = y;
/* We need to know the X, Y coordinates while creating the object,
* to insure shop boxes are empty.
* Yes, this is a horrible kludge...
*/
otmp = mkobj(let,artif);
otmp->nobj = fobj;
fobj = otmp;
place_object(otmp, x, y);
mksx = mksy = 0;
return(otmp);
}
struct obj *
mksobj_at(otyp,x,y,init)
int otyp,x,y;
boolean init;
{
register struct obj *otmp;
mksx = x; mksy = y;
otmp = mksobj(otyp,init,TRUE);
otmp->nobj = fobj;
place_object(otmp, x, y);
mksx = mksy = 0;
return((fobj = otmp));
}
struct obj *
mkobj(let, artif)
char let;
boolean artif;
{
register int tprob, i, prob = rnd(1000);
if(let == RANDOM_CLASS) {
const struct icp *iprobs =
#ifdef REINCARNATION
(Is_rogue_level(&u.uz)) ?
(const struct icp *)rogueprobs :
#endif
Inhell ? (const struct icp *)hellprobs :
(const struct icp *)mkobjprobs;
for(tprob = rnd(100);
(tprob -= iprobs->iprob) > 0;
iprobs++);
let = iprobs->ilet;
}
i = bases[letindex(let)];
while((prob -= objects[i].oc_prob) > 0) i++;
if(objects[i].oc_class != let || !OBJ_NAME(objects[i]))
panic("probtype error, let=%c i=%d", let, i);
return(mksobj(i, TRUE, artif));
}
STATIC_OVL void
mkbox_cnts(box)
/* Note: does not check to see if it overloaded the box capacity; usually
* possible only with corpses in ice boxes.
*/
struct obj *box;
{
register int n;
register struct obj *otmp, *gold = 0;
box->cobj = (struct obj *) 0;
switch(box->otyp) {
case ICE_BOX: n = 20; break;
case CHEST: n = 5; break;
case LARGE_BOX: n = 3; break;
case SACK:
case OILSKIN_SACK:
case BAG_OF_HOLDING: n = 1; break;
default: n = 0; break;
}
for (n = rn2(n+1); n > 0; n--) {
if (box->otyp == ICE_BOX) {
if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue;
/* Note: setting age to 0 is correct. Age has a different
* from usual meaning for objects stored in ice boxes. -KAA
*/
otmp->age = 0L;
} else {
register int tprob;
const struct icp *iprobs = boxiprobs;
for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
;
if (!(otmp = mkobj(iprobs->ilet, TRUE))) continue;
/* handle a couple of special cases */
if (otmp->otyp == GOLD_PIECE) {
/* 2.5 x level's usual amount; weight adjusted below */
otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75));
if (gold) { /* gold already in this box */
gold->quan += otmp->quan; /* merge */
dealloc_obj(otmp); /* note: not yet in any chain */
continue;
} else {
gold = otmp; /* remember this object */
}
} else while (otmp->otyp == ROCK) {
otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE);
if (otmp->quan > 2L) otmp->quan = 1L;
otmp->owt = weight(otmp);
}
if (box->otyp == BAG_OF_HOLDING) {
if (Is_mbag(otmp)) {
otmp->otyp = SACK;
otmp->spe = 0;
otmp->owt = weight(otmp);
} else while (otmp->otyp == WAN_CANCELLATION)
otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
}
}
otmp->nobj = box->cobj;
box->cobj = otmp;
}
if (gold) gold->owt = weight(gold); /* quantity was diddled */
return;
}
int
rndmonnum() /* select a random, common monster type */
{
register struct permonst *ptr;
register int i;
/* Plan A: get a level-appropriate common monster */
ptr = rndmonst();
if (ptr) return(monsndx(ptr));
/* Plan B: get any common monster */
do {
ptr = &mons[(i = rn2(NUMMONS))];
} while((ptr->geno & G_NOGEN) || (!Inhell && (ptr->geno & G_HELL)));
return(i);
}
#endif /* OVL1 */
#ifdef OVLB
const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS,
GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, 0};
/*ARGSUSED*/
struct obj *
mksobj(otyp, init, artif)
int otyp;
boolean init;
boolean artif;
{
int tryct;
struct obj *otmp;
char let = objects[otyp].oc_class;
otmp = newobj(0);
*otmp = zeroobj;
otmp->age = monstermoves;
otmp->o_id = flags.ident++;
otmp->quan = 1L;
otmp->oclass = let;
otmp->otyp = otyp;
otmp->dknown = index(dknowns, let) ? 0 : 1;
if (!objects[otmp->otyp].oc_uses_known)
otmp->known = 1;
if (init) switch (let) {
case WEAPON_CLASS:
otmp->quan = (otmp->otyp <= SHURIKEN) ? (long) rn1(6,6) : 1L;
if(!rn2(11)) {
otmp->spe = rne(3);
otmp->blessed = rn2(2);
} else if(!rn2(10)) {
curse(otmp);
otmp->spe = -rne(3);
} else blessorcurse(otmp, 10);
if (artif && !rn2(20))
otmp = mk_artifact(otmp, (aligntyp)A_NONE);
break;
case FOOD_CLASS:
otmp->oeaten = 0;
switch(otmp->otyp) {
case CORPSE:
/* overridden by mkcorpstat() */
do otmp->corpsenm = rndmonnum();
while (mons[otmp->corpsenm].geno & G_NOCORPSE);
break;
case EGG:
if(!rn2(3)) { /* "live" eggs */
register struct permonst *ptr;
for(tryct = 0;
(!(ptr = rndmonst()) ||
(!lays_eggs(ptr) && ptr != &mons[PM_KILLER_BEE])) &&
tryct < 100;
tryct++);
if(tryct < 100) otmp->corpsenm = monsndx(ptr);
else otmp->corpsenm = -1; /* empty */
} else otmp->corpsenm = -1; /* empty */
break;
case TIN:
if(!rn2(6)) {
otmp->spe = 1; /* spinach */
otmp->corpsenm = -1;
} else do {
otmp->corpsenm = rndmonnum();
} while (mons[otmp->corpsenm].geno & G_NOCORPSE);
blessorcurse(otmp, 10);
break;
#ifdef TUTTI_FRUTTI
case SLIME_MOLD:
otmp->spe = current_fruit;
break;
#endif
}
if (otmp->otyp == CORPSE) break;
/* fall into next case */
case GEM_CLASS:
if (otmp->otyp == LOADSTONE) curse(otmp);
else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6);
else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L;
else otmp->quan = 1L;
break;
case TOOL_CLASS:
switch(otmp->otyp) {
case TALLOW_CANDLE:
case WAX_CANDLE: otmp->spe = 1;
otmp->age = 20L * /* 400 or 200 */
(long)objects[otmp->otyp].oc_cost;
otmp->lamplit = 0;
otmp->quan = 1L +
(long)(rn2(2) ? rn2(7) : 0);
blessorcurse(otmp, 5);
break;
case BRASS_LANTERN:
case OIL_LAMP: otmp->spe = 1;
otmp->age = (long) rn1(500,1000);
otmp->lamplit = 0;
blessorcurse(otmp, 5);
break;
case MAGIC_LAMP: otmp->spe = 1;
otmp->lamplit = 0;
blessorcurse(otmp, 2);
break;
case CHEST:
case LARGE_BOX: otmp->olocked = !!(rn2(5));
otmp->otrapped = !(rn2(10));
case ICE_BOX:
case SACK:
case OILSKIN_SACK:
case BAG_OF_HOLDING: mkbox_cnts(otmp);
break;
case MAGIC_MARKER: otmp->spe = rn1(70,30);
break;
case CAN_OF_GREASE: otmp->spe = rnd(25);
blessorcurse(otmp, 10);
break;
case CRYSTAL_BALL: otmp->spe = rnd(5);
blessorcurse(otmp, 2);
break;
case HORN_OF_PLENTY:
case BAG_OF_TRICKS: otmp->spe = rnd(20);
break;
case FIGURINE: { int tryct2 = 0;
do
otmp->corpsenm = rndmonnum();
while(is_human(&mons[otmp->corpsenm])
&& tryct2++ < 30);
blessorcurse(otmp, 4);
break;
}
case BELL_OF_OPENING: otmp->spe = 3;
break;
case MAGIC_FLUTE:
case MAGIC_HARP:
case FROST_HORN:
case FIRE_HORN:
case DRUM_OF_EARTHQUAKE:
otmp->spe = rn1(5,4);
break;
}
break;
case AMULET_CLASS:
if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION ||
otmp->otyp == AMULET_OF_CHANGE ||
otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
curse(otmp);
} else blessorcurse(otmp, 10);
case VENOM_CLASS:
case CHAIN_CLASS:
case BALL_CLASS:
break;
case POTION_CLASS:
case SCROLL_CLASS:
#ifdef MAIL
if (otmp->otyp != SCR_MAIL)
#endif
blessorcurse(otmp, 4);
break;
case SPBOOK_CLASS:
blessorcurse(otmp, 17);
break;
case ARMOR_CLASS:
if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS ||
otmp->otyp == LEVITATION_BOOTS ||
otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT ||
otmp->otyp == GAUNTLETS_OF_FUMBLING ||
!rn2(11))) {
curse(otmp);
otmp->spe = -rne(3);
} else if(!rn2(10)) {
otmp->blessed = rn2(2);
otmp->spe = rne(3);
} else blessorcurse(otmp, 10);
break;
case WAND_CLASS:
if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else
otmp->spe = rn1(5,
(objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
blessorcurse(otmp, 17);
otmp->recharged = 0; /* used to control recharging */
break;
case RING_CLASS:
if(objects[otmp->otyp].oc_charged) {
blessorcurse(otmp, 3);
if(rn2(10)) {
if(rn2(10) && bcsign(otmp))
otmp->spe = bcsign(otmp) * rne(3);
else otmp->spe = rn2(2) ? rne(3) : -rne(3);
}
/* make useless +0 rings much less common */
if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3);
/* negative rings are usually cursed */
if (otmp->spe < 0 && rn2(5)) curse(otmp);
} else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION ||
#ifdef POLYSELF
otmp->otyp == RIN_POLYMORPH ||
#endif
otmp->otyp == RIN_AGGRAVATE_MONSTER ||
otmp->otyp == RIN_HUNGER || !rn2(9))) {
curse(otmp);
}
break;
case ROCK_CLASS:
switch (otmp->otyp) {
case STATUE:
if (rn2(level_difficulty()/2 + 10) > 10) {
struct obj *book;
book = mkobj(SPBOOK_CLASS,FALSE);
otmp->cobj = book;
}
/* overridden by mkcorpstat() */
otmp->corpsenm = rndmonnum();
}
break;
case GOLD_CLASS:
break; /* do nothing */
default:
impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, objects[otmp->otyp].oc_class);
return (struct obj *)0;
}
/* unique objects may have an associated artifact entry */
if (objects[otyp].oc_unique && !otmp->oartifact)
otmp = mk_artifact(otmp, (aligntyp)A_NONE);
otmp->owt = weight(otmp);
return(otmp);
}
void
bless(otmp)
register struct obj *otmp;
{
otmp->cursed = 0;
otmp->blessed = 1;
if (otmp->otyp == LUCKSTONE
|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) {
int luckbon = stone_luck(TRUE);
if(!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
else if (luckbon >= 0) u.moreluck = LUCKADD;
else u.moreluck = -LUCKADD;
} else if (otmp->otyp == BAG_OF_HOLDING)
otmp->owt = weight(otmp);
return;
}
void
unbless(otmp)
register struct obj *otmp;
{
otmp->blessed = 0;
if (otmp->otyp == LUCKSTONE
|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) {
int luckbon = stone_luck(TRUE);
if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
else if (luckbon >= 0) u.moreluck = LUCKADD;
else u.moreluck = -LUCKADD;
} else if (otmp->otyp == BAG_OF_HOLDING)
otmp->owt = weight(otmp);
}
void
curse(otmp)
register struct obj *otmp;
{
otmp->blessed = 0;
otmp->cursed = 1;
if (otmp->otyp == LUCKSTONE
|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) {
int luckbon = stone_luck(TRUE);
if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
else if (luckbon >= 0) u.moreluck = LUCKADD;
else u.moreluck = -LUCKADD;
} else if (otmp->otyp == BAG_OF_HOLDING)
otmp->owt = weight(otmp);
return;
}
void
uncurse(otmp)
register struct obj *otmp;
{
otmp->cursed = 0;
if (otmp->otyp == LUCKSTONE
|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) {
int luckbon = stone_luck(TRUE);
if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
else if (luckbon >= 0) u.moreluck = LUCKADD;
else u.moreluck = -LUCKADD;
} else if (otmp->otyp == BAG_OF_HOLDING)
otmp->owt = weight(otmp);
}
#endif /* OVLB */
#ifdef OVL1
void
blessorcurse(otmp, chance)
register struct obj *otmp;
register int chance;
{
if(otmp->blessed || otmp->cursed) return;
if(!rn2(chance))
if(!rn2(2)) {
curse(otmp);
} else {
bless(otmp);
}
return;
}
#endif /* OVL1 */
#ifdef OVLB
int
bcsign(otmp)
register struct obj *otmp;
{
return(!!otmp->blessed - !!otmp->cursed);
}
#endif /* OVLB */
#ifdef OVL0
/*
* Calculate the weight of the given object. This will recursively follow
* and calculate the weight of any containers.
*
* Note: It is possible to end up with an incorrect weight if some part
* of the code messes with a contained object and doesn't update the
* container's weight.
*/
int
weight(obj)
register struct obj *obj;
{
int wt = objects[obj->otyp].oc_weight;
if (Is_container(obj) || obj->otyp == STATUE) {
struct obj *contents;
register int cwt = 0;
if (obj->otyp == STATUE && obj->corpsenm > -1)
wt = (int)obj->quan *
((int)mons[obj->corpsenm].cwt * 3 / 2);
for(contents=obj->cobj; contents; contents=contents->nobj)
cwt += weight(contents);
/*
* The weight of bags of holding is calculated as the weight
* of the bag plus the weight of the bag's contents modified
* as follows:
*
* Bag status Weight of contents
* ---------- ------------------
* cursed 2x
* blessed x/4 + 1
* otherwise x/2 + 1
*
* The macro DELTA_CWT in pickup.c also implements these
* weight equations.
*
* Note: The above checks are performed in the given order.
* this means that if an object is both blessed and
* cursed (not supposed to happen), it will be treated
* as cursed.
*/
if (obj->otyp == BAG_OF_HOLDING)
cwt = obj->cursed ? (cwt * 2) :
(1 + (cwt / (obj->blessed ? 4 : 2)));
return wt + cwt;
}
if (obj->otyp == CORPSE && obj->corpsenm > -1)
return (int)obj->quan * mons[obj->corpsenm].cwt;
else if (obj->otyp == GOLD_PIECE)
return (int)((obj->quan + 500L) / 1000L);
return(wt ? wt*(int)obj->quan : ((int)obj->quan + 1)>>1);
}
#endif /* OVL0 */
#ifdef OVLB
void
mkgold(amount, x, y)
long amount;
int x, y;
{
register struct obj *gold = g_at(x,y);
if (amount <= 0L) amount = (long)(1 + rnd(level_difficulty()+2) * rnd(30));
if (gold) {
gold->quan += amount;
} else {
gold = mksobj_at(GOLD_PIECE,x,y,TRUE);
gold->quan = amount;
}
gold->owt = weight(gold);
}
#endif /* OVLB */
#ifdef OVL1
struct obj *
mkcorpstat(objtype, ptr, x, y, init)
int objtype; /* CORPSE or STATUE */
register struct permonst *ptr;
int x, y;
boolean init;
{
register struct obj *otmp;
if(objtype != CORPSE && objtype != STATUE)
impossible("making corpstat type %d", objtype);
otmp = mksobj_at(objtype, x, y, init);
if(otmp) {
if(ptr) otmp->corpsenm = monsndx(ptr);
else otmp->corpsenm = rndmonnum();
otmp->owt = weight(otmp);
}
return(otmp);
}
#endif /* OVL1 */
#ifdef OVLB
struct obj *
mk_tt_object(objtype, x, y)
int objtype; /* CORPSE or STATUE */
register int x, y;
{
register struct obj *otmp;
/* player statues never contain books */
if ((otmp = mksobj_at(objtype,x,y,FALSE)) != 0)
otmp = tt_oname(otmp);
return(otmp);
}
/* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
struct obj *
mk_named_object(objtype, ptr, x, y, nm, lth)
int objtype; /* CORPSE or STATUE */
register struct permonst *ptr;
int x, y;
char * nm;
register int lth;
{
struct obj *otmp;
otmp = mkcorpstat(objtype,ptr,x,y,(objtype != STATUE));
if (lth > 0) {
/* Note: oname() is safe since otmp is first in both chains */
otmp = oname(otmp, nm, FALSE);
fobj = otmp;
level.objects[x][y] = otmp;
if (is_pool(x,y)) water_damage(otmp,TRUE);
}
return(otmp);
}
boolean
is_flammable(otmp)
register struct obj *otmp;
{
int otyp = otmp->otyp;
if (objects[otyp].oc_oprop == FIRE_RES) return FALSE;
return((objects[otyp].oc_material == WOOD ||
objects[otyp].oc_material == 0));
}
#endif /* OVLB */
#ifdef OVL1
/*
* These routines maintain the single-linked lists headed in level.objects[][]
* and threaded through the nexthere fields in the object-instance structure.
*/
void
place_object(otmp, x, y)
/* put an object on top of the pile at the given location */
register struct obj *otmp;
int x, y;
{
register struct obj *otmp2 = level.objects[x][y];
if (otmp->otyp == BOULDER) block_point(x,y); /* vision */
if (otmp2 && (otmp2->otyp == BOULDER)) {
otmp->nexthere = otmp2->nexthere;
otmp2->nexthere = otmp;
} else {
otmp->nexthere = otmp2;
level.objects[x][y] = otmp;
}
if (is_pool(x,y)) water_damage(otmp,TRUE);
/* set the new object's location */
otmp->ox = x;
otmp->oy = y;
}
#endif /* OVL1 */
#ifdef OVLB
void
remove_object(otmp)
register struct obj *otmp;
{
register struct obj *odel;
if (otmp->otyp == BOULDER) unblock_point(otmp->ox,otmp->oy); /* vision */
if (otmp == level.objects[otmp->ox][otmp->oy])
level.objects[otmp->ox][otmp->oy] = otmp->nexthere;
else
for (odel = level.objects[otmp->ox][otmp->oy];
odel; odel = odel->nexthere)
if (odel->nexthere == otmp) {
odel->nexthere = otmp->nexthere;
break;
}
}
void
move_object(otmp, x, y)
register struct obj *otmp;
int x, y;
{
remove_object(otmp);
place_object(otmp, x, y);
}
#endif /* OVLB */
/*mkobj.c*/